/*
 *  Map.cpp
 *  TractionEdge
 *
 *  Created by Steven Hamilton on 20/11/09.
 *  Copyright 2009 scorch.org. All rights reserved.
 *
 */

#include <fstream>
#include <iostream>
#include <string>
#include "defines.h"
#include "Map.h"
#include "tinyxml.h"
#include "Utility.h"

#define TIXML_USE_STL

Map::Map()
{
	creatureSchema["human"]=HUMAN;
    creatureSchema["slither"]=SLITHER;
	creatureSchema["gimp"]=GIMP;
	parameterMap["squadsize"]=0;
}

Map::~Map()
{
}

void Map::loadMap(int mapNumber)
{
	Utility tool;


	objectId=WORLD.getObjectId();
	std::cout << "Map objectId = " << objectId << std::endl;
	
    //initialise map
    map.clear();
    map.resize(MAPHEIGHT);
	for (int i=0; i < MAPHEIGHT; i++)
		map[i].resize(MAPWIDTH);
	
    //load map tmx file
	std::string mapURL = "maps/map"+tool.stringFromInt(mapNumber)+".tmx";
	TiXmlDocument mapFile(mapURL.c_str());
	bool loadOkay = mapFile.LoadFile();
	if (loadOkay)
	{
		std::cout << "loaded " << mapURL << std::endl; // defined later in the tutorial
	}
	else
	{
		std::cout << "failed to load " << mapURL << std::endl;
		exit(0);
	}
	
	TiXmlHandle mapHandle(&mapFile);
	
	TiXmlElement * tileElement=mapHandle.FirstChild("map").FirstChild("layer").FirstChild("data").FirstChild("tile").ToElement();
	std::cout << "element: " << tileElement->Value() << std::endl;
	
	for (int y=0;y < map.size(); y++){
		for (int x=0;x < MAPWIDTH; x++){
			if (tileElement){
				//std::cout << "gid id=" << tileElement->Attribute("gid") << std::endl;
				int terrainId=tool.stringToInt(tileElement->Attribute("gid"));
				Terrain terrain(terrainId-1);
                terrain.isVisible=false;
				map[y][x] = terrain;
				//std::cout << map[y][x].gfxId;
				
				tileElement=tileElement->NextSiblingElement();
			}
		}
	}
	
    //load map parameter file
    std::string paramURL = "maps/map"+tool.stringFromInt(mapNumber)+".xml";
	TiXmlDocument paramFile(paramURL.c_str());
	loadOkay = paramFile.LoadFile();
	if (loadOkay)
	{
		std::cout << "Map.cpp:loaded " << paramURL << std::endl; // defined later in the tutorial
	}
	else
	{
		std::cout << "Map.cpp:failed to load " << paramURL << std::endl; // defined later in the tutorial
        exit(0);
	}
	
	//set paramaters
	TiXmlHandle paramHandle(&paramFile);
    for(TiXmlElement * itemNode=paramHandle.FirstChild("parameters").FirstChild().ToElement(); itemNode; itemNode=itemNode->NextSiblingElement() )
	{
		parameterMap[itemNode->Value()]=tool.stringToInt(itemNode->GetText());
		std::cout << "Setting " << itemNode->Value() << " to " << parameterMap[itemNode->Value()] << std::endl;
	}
	
    //process zones
	TiXmlElement * zoneNode=paramHandle.FirstChild("zone").ToElement();
	if (zoneNode) {
		for(zoneNode; zoneNode; zoneNode=zoneNode->NextSiblingElement() )
		{
			int x1,y1,x2,y2;
			zoneNode->Attribute("x1",&x1);
			zoneNode->Attribute("y1",&y1);
			zoneNode->Attribute("x2",&x2);
			zoneNode->Attribute("y2",&y2);    
			std::cout << "Map.cpp: Processing zone " << x1 << ":" << y1 << " to " << x2 << ":" << y2 << std::endl;
			
			TiXmlNode * startNode=zoneNode->FirstChild("startzone");
			if (startNode){
				std::cout << "Setting this zone as startzone" << std::endl;
				startx1=x1;
				starty1=y1;
				startx2=x2;
				starty2=y2;
			}
			
			//create creatures
			TiXmlNode * creatureNode=zoneNode->FirstChild("creature");
			if (creatureNode){
				TiXmlElement * creatureElem=creatureNode->ToElement();
				for(creatureElem; creatureElem; creatureElem=creatureElem->NextSiblingElement() )
				{
					int count;
					creatureElem->Attribute("count",&count);
					creature_t type=creatureSchema[creatureElem->Attribute("type")];
					std::cout << "Map.cpp: adding creature: " << creatureElem->Attribute("type") << " count: " << creatureElem->Attribute("count") << std::endl;
					for (int i=0;i < count;i++){
						Creature creature(type, ENEMY);
						creature.onMap=true;
                        //pick a position. If invalid pick another.
                        Position pos;
                        do {
                            pos.x=(rand() % (x2-x1))+x1;
                            pos.y=(rand() % (y2-y1))+y1;
                        } while (!isTerrainPassable(pos));
						creature.position=pos;
						WORLD.addCreature(creature);
					}
				}
			}
		}
	}
    //process texts
	TiXmlElement * introTextNode=paramHandle.FirstChild("introtext").ToElement();
	introText.append(introTextNode->GetText());
	TiXmlElement * resultTextNode=paramHandle.FirstChild("resulttext").ToElement();
    resultText.append(resultTextNode->GetText());
}

bool Map::isTileTranslucent(int x, int y)
{
	//if tile is height 1 or less then we can see over it.
	if (map[y][x].isTranslucent) return true;
	else return false;
}

bool Map::isTileVisible(Position position)
{
	if (map[position.y][position.x].isVisible) return true;
	else return false;
}

bool Map::setTileVisibility(Position position, bool flag)
{
	map[position.y][position.x].isVisible = flag;
    if (flag) map[position.y][position.x].wasVisible = flag;
}

bool Map::isTerrainPassable(Position position)
{
	if (map[position.y][position.x].height<=1)	return true;
	return false;
}

void Map::setTilePassable(Position position, bool flag)
{
	map[position.y][position.x].isPassable = flag;
}

int Map::getMoveCost(Position position)
{
	return map[position.y][position.x].moveCost;
}

void Map::damage(Position position,  Item &weapon)
{
	Terrain* tile=&map[position.y][position.x];
	if (tile->height>0) {
		tile->currentHitPoints-=weapon.properties["damage"];
		if (tile->currentHitPoints<=0) destroyTerrain(position);
	}
}

void Map::destroyTerrain(Position position)
{
	Utility tool;
    Terrain & tile=map[position.y][position.x];
	Terrain deadTerrain(tile.deadTerrain);
    std::cout << "Replacing tile " << tile.name << " with " << tool.stringFromInt(tile.deadTerrain) << std::endl;
	map[position.y][position.x] = deadTerrain;
}

std::string Map::terrainNameAt(Position position)
{
	return map[position.y][position.x].name;
}
